package net.hands.common;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * 说明:流处理工具
 * <br> 
 * <p>这是一个开源的软件，请在LGPLv3下合法使用、修改或重新发布。</p>
 * @author 陈侃(cknet@126.com, 13910090885)
 *         http://code.google.com/p/simpleframework/
 *         http://www.simpleframework.net
 */
public abstract class IoUtils {
	/**
	 * 8g缓存
	 */
	static final int BUFFER = 8 * 1024;
   /**
   * 说明:输入流转字符串
   * @param inputStream 输入流
   * @return String     字符串
   * @throws IOException
   * @update 2012-9-24 下午2:49:18
    */
	public static String getStringFromInputStream(final InputStream inputStream) throws IOException {
		return getStringFromInputStream(inputStream, "UTF-8");
	}
   /**
   * 说明:输入流转字符串
   * @param inputStream  输出流
   * @param charsetName 编码名称
   * @return String
   * @throws IOException
   * @update 2012-9-22 下午8:07:08
    */
	public static String getStringFromInputStream(final InputStream inputStream,
			final String charsetName) throws IOException {
		return getStringFromReader(new InputStreamReader(inputStream, charsetName));
	}
   /**
   * 说明:读取流转字符
   * @param reader 读取流
   * @return String
   * @throws IOException
   * @update 2012-9-24 下午2:50:33
    */
	public static String getStringFromReader(final Reader reader) throws IOException {
		BufferedReader br = null;
		try {
			br = new BufferedReader(reader); //缓存字符流
			final StringWriter sw = new StringWriter(); //字符写入流
			final PrintWriter writer = new PrintWriter(sw);//打印写入流
			String s;
			while ((s = br.readLine()) != null) {//读取每行
				writer.println(s); //写入字符中
			}
			writer.flush();//冲洗缓存通道
			return sw.toString();//转字符返回
		} finally {
			if (br != null) {
				br.close();
			}
		}
	}
   /**
   * 说明:读取流转字符数组
   * @param reader 读取流
   * @return String[]
   * @throws IOException
   * @update 2012-9-24 下午2:51:05
    */
	public static String[] getStringsFromReader(final Reader reader) throws IOException {
		BufferedReader br = null;
		try {
			br = new BufferedReader(reader);
			final List<String> l = new ArrayList<String>();//字符集合
			String s;
			while ((s = br.readLine()) != null) {
				l.add(s);
			}
			return l.toArray(new String[l.size()]);//字符集合转字符数组
		} finally {
			if (br != null) {
				br.close();
			}
		}
	}
   /**
   * 说明:创建递归目录
   * @param directory 目录
   * @return boolean
   * @update 2012-9-24 下午3:22:01
    */
	public static boolean createDirectoryRecursively(File directory) {
		if (directory == null) {//目录为空
			return false;
		} else if (directory.exists()) {//目录存在
			return !directory.isFile();//是否为文件
		} else if (!directory.isAbsolute()) {//是否为绝对目录
			directory = new File(directory.getAbsolutePath());//创建文件对象
		}
		final String parent = directory.getParent();//获得父亲目录
		if ((parent == null) || !createDirectoryRecursively(new File(parent))) {//父目录存在递归不存在返回false
			return false;
		}
		directory.mkdir();//创建目录结构
		return directory.exists();
	}
   /**
   * 说明:创建文件
   * @param file 文件
   * @return File
   * @throws IOException
   * @update 2012-9-24 下午3:30:40
    */
	public static File createFile(final File file) throws IOException {
		if (!file.exists()) {
			createDirectoryRecursively(file.getParentFile());
			file.createNewFile();
		}
		return file;
	}
   /**
   * 说明:拷贝文件
   * @param from 来源文件
   * @param to   目标文件
   * @throws IOException
   * @update 2012-9-24 下午3:43:37
    */
	public static void copyFile(final File from, final File to) throws IOException {
		final InputStream inputStream = new BufferedInputStream(new FileInputStream(from));
		copyFile(inputStream, to);
	}
   /**
   * 说明:拷贝文件
   * @param inputStream  输入流
   * @param to   目标文件
   * @throws IOException
   * @update 2012-9-24 下午3:44:34
    */
	public static void copyFile(final InputStream inputStream, final File to) throws IOException {
		createFile(to);
		OutputStream outputStream = null;
		try {
			copyStream(inputStream, outputStream = new BufferedOutputStream(new FileOutputStream(to)));
		} finally {
			if (inputStream != null) {
				inputStream.close();
			}
			if (outputStream != null) {
				outputStream.close();
			}
		}
	}
   /**
   * 容量单位
   */
	private static long kb = 1024, mb = kb * 1024, gb = mb * 1024;
   /**
   * 说明:大小换算成容量单位字符
   * @param size 文件大小
   * @return String
   * @update 2012-9-24 下午4:39:36
    */
	public static String toFileSize(final long size) {
		if (size < 0) {
			return "";
		} else if (size > gb) {
			final double d = (double) size / (double) gb;
			return Convert.toString(NumberUtils.formatDouble(d)) + " GB";
		} else if (size > mb) {
			final double d = (double) size / (double) mb;
			return Convert.toString(NumberUtils.formatDouble(d)) + " MB";
		} else if (size > kb) {
			final double d = (double) size / (double) kb;
			return Convert.toString(NumberUtils.formatDouble(d)) + " KB";
		} else {
			return Convert.toString(size) + " B";
		}
	}
   /**
   * 说明:容量单位字符转长整型大小
   * @param size 文件大小
   * @return long
   * @update 2012-9-24 下午4:40:36
    */
	public static long toFileSize(String size) {
		if (size != null) {
			size = size.toUpperCase();
			final StringBuilder sb = new StringBuilder();
			final StringBuilder sb2 = new StringBuilder();
			for (final char c : size.toCharArray()) {
				if (c == 'B' || c == 'K' || c == 'M' || c == 'G') {
					sb2.append(c);
					continue;
				}
				sb.append(c);
			}
			char c;
			if (sb2.length() == 0 || (c = sb2.charAt(0)) == 'B') {
				return Convert.toLong(sb.toString());
			} else {
				final double l = Convert.toDouble(sb.toString());
				if (c == 'G') {
					return (long) (gb * l);
				} else if (c == 'M') {
					return (long) (mb * l);
				} else if (c == 'K') {
					return (long) (kb * l);
				}
			}
		}
		return 0;
	}
   /**
    * 
   * 说明:获得文件目录的大小
   * @param directory 文件目录
   * @return long
   * @update 2012-9-24 下午4:42:18
    */
	public static long sizeOfDirectory(final File directory) {
		if (!directory.exists()) {//目录不存在 返回0l
			return 0l;
		}

		if (!directory.isDirectory()) {//目录为文件,获得文件大小
			return directory.length();
		}

		long size = 0;
		final File[] files = directory.listFiles();//获得目录中文件集合
		if (files == null) {
			return 0;
		}
		for (int i = 0; i < files.length; i++) {//循环文件和子目录集合 获得每个文件大小和子目录大小 计算综合
			final File file = files[i];
			if (file.isDirectory()) {
				size += sizeOfDirectory(file);//递归
			} else {
				size += file.length();
			}
		}
		return size;
	}
   /**
   * 说明:输入流东西拷贝到输出流中
   * @param inputStream 输入流
   * @param outputStream  输出流
   * @return int  
   * @throws IOException
   * @update 2012-9-24 下午4:46:02
    */
	public static int copyStream(final InputStream inputStream, final OutputStream outputStream)
			throws IOException {
		if (inputStream == null || outputStream == null) {
			return 0;
		}
		int result = 0;
		final byte[] buf = new byte[BUFFER];//缓存字节数组
		for (;;) {//循环
			final int numRead = inputStream.read(buf);
			if (numRead == -1) {
				break;//知道读取-1 接受循环
			}
			outputStream.write(buf, 0, numRead);
			result += numRead;
		}
		outputStream.flush();
		return result;
	}
   /**
    * 获得硬件地址方法
    */
	private static Method getHardwareAddressMethod;
	static {
		try {
			getHardwareAddressMethod = NetworkInterface.class.getMethod("getHardwareAddress");
		} catch (final NoSuchMethodException e) {
		}
	}
   /**
   * 说明:获得mac广播地址字节数组
   * @return byte[]
   * @throws IOException
   * @update 2012-9-24 下午4:57:07
    */
	public static byte[] getMacAddressBytes() throws IOException {
		//搜索绑定了指定 Internet 协议 (IP) 地址的网络接口的便捷方法
		final NetworkInterface ni = NetworkInterface.getByInetAddress(InetAddress.getLocalHost());
		if (getHardwareAddressMethod != null) {//如果无此方法
			return (byte[]) ClassUtils.invoke(getHardwareAddressMethod, ni);
		}
		//mac地址类获得
		return MacAddress.getMacAddress().getBytes();
	}
   /**
   * 说明:删除所文件 包括目录自己
   * @param dir 文件
   * @throws IOException
   * @update 2012-9-24 下午5:01:26
    */
	public static void deleteAll(final File dir) throws IOException {
		deleteAll(dir, true);
	}
   /**
   * 说明:删除所有文件目录
   * @param dir 文件目录
   * @param self 是否删除自己
   * @throws IOException
   * @update 2012-9-24 下午5:12:24
    */
	public static void deleteAll(final File dir, final boolean self) throws IOException {
		if (!dir.exists()) {
			return;
		}
		if (!dir.isDirectory()) {
			dir.delete();
			return;
		}
		final String[] list = dir.list();
		if (list != null) {
			for (final String element : list) {
				final File child = new File(dir, element);
				deleteAll(child);
			}
		}
		if (self) {
			dir.delete();
		}
	}

	/*----------------------------- zip utils ----------------------------*/
  /**
  * 说明:解压
  * @param in 输入流
  * @param target 目标
  * @throws IOException
  * @update 2012-9-24 下午5:14:16
   */
	public static void unzip(final InputStream in, final String target) throws IOException {
		unzip(in, target, true);
	}
   /**
   * 说明:解压
   * @param in 输出流
   * @param target  目标
   * @param rewrite 是否写
   * @throws IOException
   * @update 2012-9-24 下午5:18:20
    */
	public static void unzip(final InputStream in, final String target, final boolean rewrite)
			throws IOException {
		//解压
		unzip(in, target, rewrite, new IUnZipHandle() {
         /**
          * 
         (non-Javadoc)  
         * @see net.hands.common.IoUtils.IUnZipHandle#doFile(java.util.zip.ZipInputStream, java.io.File)  
         * @update 2012-9-24 下午5:39:51
          */
			@Override
			public void doFile(final ZipInputStream is, final File destFile) throws IOException {
				final BufferedOutputStream oStream = new BufferedOutputStream(new FileOutputStream(
						destFile));
				try {
					copyStream(is, oStream);//拷贝流
				} finally {
					if (oStream != null) {
						oStream.close();
					}
				}
			}
		});
	}
   /**
   * 说明:解压文件
   * @param in  输入流 内有未压缩钱文件
   * @param target  目标路径
   * @param rewrite  是否写入
   * @param unzipHandle  实现解压处理接口类
   * @throws IOException
   * @update 2012-9-24 下午5:20:39
    */
	public static void unzip(final InputStream in, String target, final boolean rewrite,
			final IUnZipHandle unzipHandle) throws IOException {
		if (target.charAt(target.length() - 1) != File.separatorChar) {//如果目标第一个字符不等于文件分隔符
			target += File.separatorChar; //添加一个分隔符
		}
		ZipInputStream is;//压缩输入流
		if (in instanceof ZipInputStream) {//是都是压缩输入流
			is = (ZipInputStream) in;
		} else {//不是 创建压缩输入流 
			is = new ZipInputStream(new BufferedInputStream(in));
		}
		try {
			ZipEntry entry; //压缩实体
			while ((entry = is.getNextEntry()) != null) {
				final String entryName = entry.getName();//获得压缩实体名字
				final int index = entryName.lastIndexOf("/");//最后一个/
				if (index > 0) {
					//创建解压后存放目录
					createDirectoryRecursively(new File(target + entryName.substring(0, index)));
				}
				if (entry.isDirectory()) {
					continue;
				}
            //存放目标文件
				final File destFile = new File(target + entryName);
				if (rewrite || !destFile.exists()) {//判断文件存在,是否写入
					unzipHandle.doFile(is, destFile);
				}
			}
		} finally {
			if (is != null) {
				in.close();
			}
		}
	}
   /**
    * 
   * 说明:解压处理接口
   * @update 2012-9-24 下午5:19:42
    */
	public static interface IUnZipHandle {
      /**
      * 说明:处理文件
      * @param is 输入流
      * @param destFile  解压后文件
      * @throws IOException
      * @update 2012-9-24 下午5:20:03
       */
		void doFile(ZipInputStream is, File destFile) throws IOException;
	}
}
